import 'package:dio/dio.dart';
import 'package:easy_chat_app/commons/ServerConfig.dart';
import 'package:easy_chat_app/commons/enum/AppLoginStateEnum.dart';
import 'package:easy_chat_app/commons/model/AppLoginReq.dart';
import 'package:easy_chat_app/commons/model/AppRegisterReq.dart';
import 'package:easy_chat_app/commons/model/AppSendMessageReq.dart';
import 'package:easy_chat_app/commons/model/AppTokenInfo.dart';
import 'package:easy_chat_app/commons/model/AppUserDetail.dart';
import 'package:easy_chat_app/commons/model/Conversation.dart';
import 'package:easy_chat_app/commons/model/GetChatGroupDetailResultData.dart';
import 'package:easy_chat_app/commons/model/GetContactsUserInfoResultData.dart';
import 'package:easy_chat_app/commons/model/GetContactsListItem.dart';
import 'package:easy_chat_app/commons/model/GetFriendRequestListResultData.dart';
import 'package:easy_chat_app/commons/model/GetUserChatGroupInfoListItem.dart';
import 'package:easy_chat_app/commons/model/GetUserPublicInfoByCodeResultData.dart';
import 'package:easy_chat_app/commons/model/InboxMessage.dart';
import 'package:easy_chat_app/commons/model/OutboxMessage.dart';
import 'package:easy_chat_app/commons/model/Result.dart';
import 'package:easy_chat_app/commons/model/UploadUserHeadPortraitVO.dart';
import 'package:easy_chat_app/commons/utils/RouteUtils.dart';
import 'package:easy_chat_app/commons/utils/StringUtils.dart';
import 'package:easy_chat_app/commons/utils/TokenUtils.dart';
import 'package:logger/logger.dart';

import '../../mobile/page/MobileUserHeadPortraitPreviewPage.dart';

class HttpUtils {
  static Logger logger = Logger();

  static final Dio _dio = createDIO();

  static const baseURL =
      "$ecHttpProtocolType://$ecServerIpAddress:$ecServerPort";

  static Dio createDIO() {
    var options = BaseOptions(
        contentType: "application/json;charset=UTF-8", baseUrl: baseURL);
    Dio dio = Dio(options);
    dio.interceptors.add(TokenInterceptor());
    return dio;
  }

  static Future<Result<String>> login(String phone, String password) async {
    AppLoginReq appLoginReq = AppLoginReq(phone, password);
    logger.i("appLoginReq:$appLoginReq");
    Response<Map<String, dynamic>> resp =
        await _dio.post("/app/user/login", data: appLoginReq.toJson());
    Result<String> result = Result.fromJson(resp.data!, (json) {
      return json.toString();
    });
    return result;
  }

  static Future<Result<String>> register(String phone, String password) async {
    AppRegisterReq appRegisterApp = AppRegisterReq(phone, password);
    logger.i("appRegisterApp:$appRegisterApp");
    Response<Map<String, dynamic>> resp =
        await _dio.post("/app/user/register", data: appRegisterApp.toJson());
    Result<String> result = Result.fromJson(resp.data!, (json) {
      return json.toString();
    });
    return result;
  }

  static Future<Result<String?>> logout() async {
    Response<Map<String, dynamic>> resp = await _dio.post("/app/user/logout");
    Result<String?> result = Result.fromJson(resp.data!, (json) {
      return null;
    });
    return result;
  }

  static Future<Result<AppTokenInfo>> getLoginUserInfo() async {
    Response<Map<String, dynamic>> resp =
        await _dio.get("/app/user/getLoginUserInfo");
    Result<AppTokenInfo> result = Result.fromJson(resp.data!, (json) {
      return AppTokenInfo.fromJson(json as Map<String, dynamic>);
    });
    return result;
  }

  static Future<Result<AppUserDetail>> getAppUserDetail() async {
    Response<Map<String, dynamic>> resp =
        await _dio.get("/app/user/getAppUserDetail");
    Result<AppUserDetail> result = Result.fromJson(resp.data!, (json) {
      return AppUserDetail.fromJson(json as Map<String, dynamic>);
    });
    return result;
  }

  static Future<Result> changeUserNickName(String newNickName) async {
    Response<Map<String, dynamic>> resp = await _dio.post(
        "/app/user/changeUserNickName",
        data: {"newNickName": newNickName});
    Result result = Result.fromJson(resp.data!, (json) {
      return null;
    });
    return result;
  }

  static Future<Result<UploadUserHeadPortraitVO?>> uploadUserHeadPortrait(
      EditImageInfo editImageInfo) async {
    String contentType = "";
    if (editImageInfo.imageType == ImageType.jpg) {
      contentType = "image/jpeg";
    }
    Response<Map<String, dynamic>> resp =
        await _dio.post("/app/user/uploadUserHeadPortrait",
            data: FormData.fromMap({
              "file": MultipartFile.fromBytes(editImageInfo.data!,
                  filename: "userHeadPortrait.jpg")
            }),
            options: Options(contentType: contentType));
    Result<UploadUserHeadPortraitVO?> result =
        Result.fromJson(resp.data!, (json) {
      if (json != null && json is Map<String, dynamic>) {
        return UploadUserHeadPortraitVO.fromJson(json);
      }
      return null;
    });
    logger.i("result: $result");
    return result;
  }

  static Future<Result<List<GetContactsListItem>>> getContactsList() async {
    Response<Map<String, dynamic>> resp =
        await _dio.get("/app/contact/getContactsList");
    Result<List<GetContactsListItem>> result =
        Result.fromJson(resp.data!, (json) {
      if (json == null) {
        return [];
      }
      List<GetContactsListItem> itemList = [];
      if (json is List) {
        for (var value in json) {
          if (value is Map<String, dynamic>) {
            itemList.add(GetContactsListItem.fromJson(value));
          }
        }
      }
      return itemList;
    });
    // logger.i("result:$result");
    return result;
  }

  static Future<Result<GetContactsUserInfoResultData?>> getContactsUserInfo(
      int contactsUserId) async {
    Response<Map<String, dynamic>> resp = await _dio
        .get("/app/contact/getContactsUserInfo?contactsUserId=$contactsUserId");
    Result<GetContactsUserInfoResultData?> result =
        Result.fromJson(resp.data!, (json) {
      if (json == null) {
        return null;
      }
      return GetContactsUserInfoResultData.fromJson(
          json as Map<String, dynamic>);
    });
    // logger.i("result:$result");
    return result;
  }

  static Future<Result<bool>> checkIsContact(int userId) async {
    Response<Map<String, dynamic>> resp =
        await _dio.get("/app/contact/checkIsContact?userId=$userId");
    Result<bool> result = Result.fromJson(resp.data!, (json) {
      if (json == null) {
        return false;
      }
      return json as bool;
    });
    // logger.i("result:$result");
    return result;
  }

  static Future<Result<Conversation?>> getOrCreateConversation(
      int type, int? friendUserId, int? chatGroupId) async {
    Response<Map<String, dynamic>> resp = await _dio
        .post("/app/conversation/getOrCreateConversation", data: {
      "friendUserId": friendUserId,
      "type": type,
      "chatGroupId": chatGroupId
    });
    Result<Conversation?> result = Result.fromJson(resp.data!, (json) {
      if (json == null) {
        return null;
      }
      return Conversation.fromJson(json as Map<String, dynamic>);
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result<Conversation?>> getConversation(
      int? friendUserId, int? chatGroupId) async {
    Response<Map<String, dynamic>> resp = await _dio.post(
        "/app/conversation/getConversation",
        data: {"friendUserId": friendUserId, "chatGroupId": chatGroupId});
    Result<Conversation?> result = Result.fromJson(resp.data!, (json) {
      if (json == null) {
        return null;
      }
      return Conversation.fromJson(json as Map<String, dynamic>);
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result<List<Conversation>>> getConversationByIdList(
      List<int> idList) async {
    logger.i("idList: $idList");
    Response<Map<String, dynamic>> resp = await _dio
        .post("/app/conversation/getConversationByIdList", data: idList);
    Result<List<Conversation>> result = Result.fromJson(resp.data!, (json) {
      List<Conversation> conversationList = [];
      if (json != null && json is List) {
        for (var jsonItem in json) {
          conversationList.add(Conversation.fromJson(jsonItem));
        }
      }
      return conversationList;
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result<InboxMessage?>> sendMessage(
      AppSendMessageReq sendMessageReq) async {
    Response<Map<String, dynamic>> resp = await _dio
        .post("/app/inboxMessage/sendMessage", data: sendMessageReq.toJson());
    Result<InboxMessage?> result = Result.fromJson(resp.data!, (json) {
      if (json == null) {
        return null;
      }
      return InboxMessage.fromJson(json as Map<String, dynamic>);
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result<List<OutboxMessage>>> getNewOutboxMessageList() async {
    Response<Map<String, dynamic>> resp =
        await _dio.get("/app/outboxMessage/getNewOutboxMessage");
    Result<List<OutboxMessage>> result = Result.fromJson(resp.data!, (json) {
      List<OutboxMessage> resultList = [];
      if (json == null) {
        return resultList;
      }
      if (json is List) {
        for (var value in json) {
          Map<String, dynamic> jsonObj = value;
          resultList.add(OutboxMessage.fromJson(jsonObj));
        }
      }
      return resultList;
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result<Object?>> batchACKOutboxMessage(
      List<int> outboxMessageIdList) async {
    Response<Map<String, dynamic>> resp = await _dio.post(
        "/app/outboxMessage/batchACKOutboxMessage",
        data: {"outboxMessageIdList": outboxMessageIdList});
    Result<Object?> result = Result.fromJson(resp.data!, (json) {
      return null;
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result<Conversation?>> createChatGroup(
      Set<int> friendUserIdSet) async {
    Response<Map<String, dynamic>> resp = await _dio.post(
        "/app/chatGroup/createChatGroup",
        data: {"friendUserIdSet": friendUserIdSet.toList()});
    Result<Conversation?> result = Result.fromJson(resp.data!, (json) {
      return Conversation.fromJson(json as Map<String, dynamic>);
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result<List<GetUserChatGroupInfoListResultData>>>
      getUserChatGroupInfoList() async {
    Response<Map<String, dynamic>> resp =
        await _dio.get("/app/chatGroup/getUserChatGroupInfoList");
    Result<List<GetUserChatGroupInfoListResultData>> result =
        Result.fromJson(resp.data!, (json) {
      List<GetUserChatGroupInfoListResultData> resultList = [];
      if (json != null && json is List) {
        for (Map<String, dynamic> value in json) {
          resultList.add(GetUserChatGroupInfoListResultData.fromJson(value));
        }
      }
      return resultList;
    });
    logger.i("resultList:$result");
    return result;
  }

  static Future<Result<GetUserPublicInfoByCodeResultData>>
      getUserPublicInfoByCode(String code) async {
    Response<Map<String, dynamic>> resp =
        await _dio.get("/app/user/getUserPublicInfoByCode?code=$code");
    Result<GetUserPublicInfoByCodeResultData> result =
        Result.fromJson(resp.data!, (json) {
      return GetUserPublicInfoByCodeResultData.fromJson(
          json as Map<String, dynamic>);
    });
    logger.i("resultList:$result");
    return result;
  }

  static Future<Result<GetChatGroupDetailResultData?>> getChatGroupDetail(
      int chatGroupId) async {
    Response<Map<String, dynamic>> resp = await _dio
        .get("/app/chatGroup/getChatGroupDetail?chatGroupId=$chatGroupId");
    Result<GetChatGroupDetailResultData?> result =
        Result.fromJson(resp.data!, (json) {
      return GetChatGroupDetailResultData.fromJson(
          json as Map<String, dynamic>);
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result> quitChatGroup(int chatGroupId) async {
    Response<Map<String, dynamic>> resp = await _dio.post(
        "/app/chatGroup/quitChatGroup",
        data: {"chatGroupId": chatGroupId});
    Result result = Result.fromJson(resp.data!, (json) {
      return null;
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result> deleteContacts(int contactsUserId) async {
    Response<Map<String, dynamic>> resp = await _dio.post(
        "/app/contact/deleteContact",
        data: {"contactsUserId": contactsUserId});
    Result result = Result.fromJson(resp.data!, (json) {
      return null;
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result> createFriendRequest(int targetUserId) async {
    Response<Map<String, dynamic>> resp = await _dio.post(
        "/app/friendRequest/createFriendRequest",
        data: {"targetUserId": targetUserId});
    Result result = Result.fromJson(resp.data!, (json) {
      return null;
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result<GetFriendRequestListResultData>>
      getFriendRequestList() async {
    Response<Map<String, dynamic>> resp =
        await _dio.get("/app/friendRequest/getFriendRequestList");
    Result<GetFriendRequestListResultData> result =
        Result.fromJson(resp.data!, (json) {
      return GetFriendRequestListResultData.fromJson(
          json as Map<String, dynamic>);
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result> batchChangeReadStatus2Read(
      List<int> friendRequestIdList) async {
    Response<Map<String, dynamic>> resp = await _dio.post(
        "/app/friendRequest/batchChangeReadStatus2Read",
        data: {"idList": friendRequestIdList});
    Result result = Result.fromJson(resp.data!, (json) {
      return null;
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result> acceptFriendRequest(int id) async {
    Response<Map<String, dynamic>> resp = await _dio
        .post("/app/friendRequest/acceptFriendRequest", data: {"id": id});
    Result result = Result.fromJson(resp.data!, (json) {
      return null;
    });
    logger.i("result:$result");
    return result;
  }

  static Future<Result> rejectFriendRequest(int id) async {
    Response<Map<String, dynamic>> resp = await _dio
        .post("/app/friendRequest/rejectFriendRequest", data: {"id": id});
    Result result = Result.fromJson(resp.data!, (json) {
      return null;
    });
    logger.i("result:$result");
    return result;
  }
}

class TokenInterceptor extends Interceptor {
  Logger logger = Logger();

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    logger.i('REQUEST[${options.method}] => PATH: ${options.path}');
    options.headers[TokenUtils.tokenStoreKey] = TokenUtils.token();
    super.onRequest(options, handler);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    String? tokenStatusCodeStr = response.headers.value("tokenStatusCode");
    // logger.i("tokenStatusCodeStr: $tokenStatusCodeStr");
    if (StringUtils.isNotEmpty(tokenStatusCodeStr)) {
      int tokenStatusCode = int.parse(tokenStatusCodeStr!);
      if (AppLoginStatusEnum.tokenTimeout.code == tokenStatusCode) {
        logger.i("登录超时: $tokenStatusCodeStr");
        RouteUtils.route2MobileLoginPageAndCleanStack();
        return;
      }
    }
    super.onResponse(response, handler);
  }
}
